/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.engine.runtime.datalist;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.EntityNotFoundException;
import cn.easyplatform.contexts.ListContext;
import cn.easyplatform.contexts.RecordContext;
import cn.easyplatform.dao.BizDao;
import cn.easyplatform.dos.FieldDo;
import cn.easyplatform.dos.Record;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.interceptor.CommandContext;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.support.sql.SqlParser;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.util.RuntimeUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public final class DataListUtils {

	static String parse(CommandContext cc, RecordContext rc, String content) {
		char[] cs = content.toCharArray();
		int len = cs.length;
		StringBuilder sb = new StringBuilder();
		StringBuilder tmp = new StringBuilder();
		for (int i = 0; i < len; i++) {
			if (cs[i] == '#' && i < len - 1 && cs[i + 1] == '{') {
				tmp.setLength(0);
				i += 2;
				while (i < len) {
					if (cs[i] == '}')
						break;
					else
						tmp.append(cs[i]);
					i++;
				}
				String name = tmp.toString();
				if (name.startsWith("'")) {// i18n#{'xxx'}
					String code = name.substring(1, name.length() - 1);
					sb.append(cc.getLabel(code));
				} else {
					sb.append(rc.getValue(name));
				}
			} else
				sb.append(cs[i]);
		}
		tmp = null;
		return sb.toString();
	}

	static String parsePanel(CommandContext cc, RecordContext rc, String panel) {
		// Map<String, String> resources = null;
		char[] cs = panel.toCharArray();
		int len = cs.length;
		StringBuilder sb = new StringBuilder();
		StringBuilder tmp = new StringBuilder();
		for (int i = 0; i < len; i++) {
			if (cs[i] == '#' && i < len - 1 && cs[i + 1] == '{') {
				tmp.setLength(0);
				int j = i - 1;
				i += 2;
				while (i < len) {
					if (cs[i] == '}')
						break;
					else
						tmp.append(cs[i]);
					i++;
				}
				String name = tmp.toString();
				tmp.setLength(0);
				byte mark = -1;
				for (; j > 0; j--) {
					if (cs[j] == '"') {
						while (true) {
							if (cs[--j] != ' ')
								break;
						}
						mark = 0;
					}
					if (mark == 0 && cs[j] == '=') {
						while (true) {
							if (cs[--j] != ' ')
								break;
						}
						mark = 1;
					}
					if (mark == 1) {
						tmp.append(cs[j]);
						if (cs[j] == ' ')
							break;
					}
				}
				String attribute = tmp.toString().trim();
				if (!attribute.equals("di")) {
					if (name.startsWith("'")) {// i18n#{'xxx'}
						String code = name.substring(1, name.length() - 1);
						// if (resources == null)
						// resources = cc.getLabels();
						// sb.append(resources.get(code));
						sb.append(cc.getLabel(code));
					} else {
						sb.append(rc.getValue(name));
					}
				} else
					sb.append("#{").append(name).append("}");
			} else
				sb.append(cs[i]);
		}
		tmp = null;
		cs = null;
		return sb.toString();
	}

	public static final Object[] wrapRow(CommandContext cc, ListContext lc,
			RecordContext rc) {
		List<ListHeaderVo> headers = lc.getHeaders();
		int size = headers.size();
		Object[] data = new Object[size];
		TableBean tb = null;
		String dbId = null;
		for (int i = 0; i < size; i++) {
			ListHeaderVo hv = headers.get(i);
			if (!Strings.isBlank(hv.getSql())) {// 自定义源
				if (!Strings.isBlank(lc.getBean().getTable()) && tb == null) {
					tb = cc.getEntity(lc.getBean().getTable());
					dbId = tb.getSubType();
				}
				if (!Strings.isBlank(hv.getField())
						&& !Strings.isBlank(hv.getSqlSeparator())) {// 多重值
					String sql = hv.getSql();
					FieldDo field = rc.getField(hv.getField());
					if (field.getValue() != null
							&& !Strings.isBlank(field.getValue().toString())) {
						String[] strs = field.getValue().toString()
								.split("\\" + hv.getSqlSeparator());
						int pos = sql.toUpperCase().indexOf(" WHERE ");
						String s = sql.substring(pos + 6).trim();
						StringBuilder sb = new StringBuilder(sql.substring(0,
								pos));
						sb.append(" WHERE (");
						for (int j = 0; j < strs.length; j++) {
							sb.append(s);
							if (j < strs.length - 1)
								sb.append(" OR ");
						}
						sb.append(")");
						sql = sb.toString();
						List<FieldDo> params = new ArrayList<FieldDo>(
								strs.length);
						for (int j = 0; j < strs.length; j++) {
							FieldDo param = new FieldDo(hv.getType());
							param.setName(hv.getField());
							if (hv.getType() != FieldType.VARCHAR)
								param.setValue(RuntimeUtils.castTo(param,
										strs[j]));
							else
								param.setValue(strs[j]);
							params.add(param);
						}
						BizDao dao = cc.getBizDao(dbId);
						List<FieldDo[]> result = dao.selectList(sql, params);
						if (result.isEmpty()) {
							data[i] = field.getValue();
						} else {
							sb.setLength(0);
							Iterator<FieldDo[]> itr = result.iterator();
							while (itr.hasNext()) {
								sb.append(itr.next()[0].getValue());
								if (itr.hasNext())
									sb.append(hv.getSqlSeparator());
							}
							data[i] = sb.toString();
						}
					} else
						data[i] = field.getValue();
				} else {
					SqlParser<FieldDo> sp = RuntimeUtils.createSqlParser(FieldDo.class);
					String sql = sp.parse(hv.getSql(), rc);
					BizDao dao = cc.getBizDao(dbId);
					FieldDo fd = dao.selectObject(sql, sp.getParams());
					if (fd != null)
						data[i] = fd.getValue();
				}
			} else {
				FieldDo f = rc.getFieldQuietly(hv.getName());
				if (f != null)
					data[i] = f.getValue();
			}
		}
		return data;
	}

	public static FieldDo[] getRow(CommandContext cc, ListContext lc,
			Object[] keys) {
		if (lc.isCustom()) {
			List<FieldDo> result = new ArrayList<FieldDo>();
			int len = lc.getHeaders().size();
			for (int index = 0; index < len; index++) {
				ListHeaderVo lvh = lc.getHeaders().get(index);
				if (!Strings.isBlank(lvh.getField())) {
					FieldDo field = new FieldDo(lvh.getType());
					field.setName(lvh.getField());
					field.setValue(keys[index]);
					result.add(field);
				}
			}
			FieldDo[] data = new FieldDo[result.size()];
			result.toArray(data);
			return data;
		} else {
			TableBean tb = cc.getEntity(lc.getBean().getTable());
			if (tb == null)
				throw new EntityNotFoundException(EntityType.TABLE.getName(),
						lc.getBean().getTable());
			BizDao dao = cc.getBizDao(tb.getSubType());
			StringBuilder sb = new StringBuilder();
			sb.append("select * from ").append(tb.getId()).append(" where ");
			// sb.append(lc.getResultSql()).append(" where ");
			List<FieldDo> params = RuntimeUtils.createPrimaryKey(tb, keys, sb);
			FieldDo[] data = dao.selectOne(sb.toString(), params);
			if (data == null)
				throw new EasyPlatformWithLabelKeyException(
						"table.record.not.found", tb.getId(), Lang.concat(keys)
								.toString());
			return data;
		}
	}

	public static Record getRecord(CommandContext cc, ListContext lc,
			Object[] keys) {
		if (lc.isCustom()) {
			int len = lc.getHeaders().size();
			Record data = new Record();
			for (int index = 0; index < len; index++) {
				ListHeaderVo lvh = lc.getHeaders().get(index);
				if (!Strings.isBlank(lvh.getField())) {
					FieldDo field = new FieldDo(lvh.getType());
					field.setName(lvh.getField());
					field.setValue(keys[index]);
					data.set(field);
				}
			}
			return data;
		} else {
			TableBean tb = cc.getEntity(lc.getBean().getTable());
			if (tb == null)
				throw new EntityNotFoundException(EntityType.TABLE.getName(),
						lc.getBean().getTable());
			BizDao dao = cc.getBizDao(tb.getSubType());
			Record data = dao.selectByKey(tb,
					RuntimeUtils.createPrimaryKey(tb, keys, null));
			if (data == null)
				throw new EasyPlatformWithLabelKeyException(
						"table.record.not.found", tb.getId(), Lang.concat(keys)
								.toString());
			return data;
		}
	}

	public final static List<ListRowVo> loadData(CommandContext cc,
			ListContext lc) {
		List<RecordContext> rcl = lc.getRecords();
		List<ListRowVo> result = new ArrayList<ListRowVo>();
		for (RecordContext rc : rcl) {
			if (rc.getParameterAsChar("814") != 'D') {
				ListRowVo row = new ListRowVo(rc.getKeyValues(),
						wrapRow(cc, lc, rc),
						rc.getParameterAsBoolean("853"));
				result.add(row);
			}
		}
		return result;
	}
}
